<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- AdThrive Head Tag Manual -->
    <script data-no-optimize="1" data-cfasync="false">
      (function (w, d) {
        w.adthrive = w.adthrive || {};
        w.adthrive.cmd = w.adthrive.cmd || [];
        w.adthrive.plugin = "adthrive-ads-manual";
        w.adthrive.host = "ads.adthrive.com";
        var s = d.createElement("script");
        s.async = true;
        s.referrerpolicy = "no-referrer-when-downgrade";
        s.src =
          "https://" +
          w.adthrive.host +
          "/sites/643436a4e6d20859e40a446b/ads.min.js?referrer=" +
          w.encodeURIComponent(w.location.href) +
          "&cb=" +
          (Math.floor(Math.random() * 100) + 1);
        var n = d.getElementsByTagName("script")[0];
        n.parentNode.insertBefore(s, n);
      })(window, document);
    </script>
    <!-- End of AdThrive Head Tag -->

    <!-- Global site tag (gtag.js) - Google Analytics -->

    <script
      async
      src="https://www.googletagmanager.com/gtag/js?id=UA-79254642-6"
    ></script>

    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag() {
        dataLayer.push(arguments);
      }
      gtag("js", new Date());

      gtag("config", "UA-79254642-6");
    </script>

    <meta charset="utf-8" />
    <title>Zooming in d3.js</title>
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <meta
      name="description"
      content="How zooming works in d3.js: a set of tiny examples with code illustrating different techniques"
    />
    <meta
      name="keywords"
      content="Data,Dataviz,Datavisualization,Javascript, JS, d3.js, axis, x, y, brushing"
    />
    <meta name="author" content="Yan Holtz" />
    <link rel="icon" href="../img/logo/D3_single_small.png" />

    <meta property="og:title" content="Zooming in d3.js" />
    <meta property="og:image" content="img/overview_RGG.png" />
    <meta
      property="og:description"
      content="How zooming works in d3.js: a set of tiny examples with code illustrating different techniques."
    />

    <!-- Bootstrap core CSS -->
    <link href="../vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" />

    <!-- Custom fonts for this template -->
    <link
      href="../vendor/font-awesome/css/font-awesome.min.css"
      rel="stylesheet"
      type="text/css"
    />

    <!-- Custom styles for this template -->
    <link href="../css/agency.css" rel="stylesheet" />

    <!-- PRISM -->
    <script src="../LIB/prism.js"></script>
    <link href="../LIB/prism.css" rel="stylesheet" />

    <!-- D3.JS v4 -->
    <script src="../js/d3.v4.js"></script>

    <!-- JQUERY -->
    <script src="../vendor/jquery/jquery.min.js"></script>

    <!-- HTML TO CANVAS -->
    <script src="../js/html2canvas.js"></script>

    <!-- Function to parse html and js code chunks made by Yan Holtz -->
    <script src="../js/myParser.js"></script>

    <!-- Bootstrap js -->
    <script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
    <script src="../js/agency.min.js"></script>
  </head>

  <body data-spy="scroll" data-target="#myScrollspy" data-offset="1">
    <!-- THIS ALLOWS TO INSERT THE MENU THAT IS STORED IN A MENU.HTML FILE-->
    <nav class="navbar navbar-expand-lg fixed-top" id="mainNav"></nav>
    <script>
      $(function () {
        $("#mainNav").load("../html_chunk/menu.html");
      });
    </script>

    <!-- THIS ALLOWS TO INSERT THE MODAL OF THE MENU THAT IS STORED IN A MENU_MODAL.HTML FILE-->
    <div id="modal_menu_insertion"></div>
    <script>
      $(function () {
        $("#modal_menu_insertion").load("../html_chunk/menu_modal.html");
      });
    </script>

    <!-- Header = title  + social media + a few lines of general description-->
    <header class="masthead" style="padding-top: 150px; padding-bottom: 80px">
      <div class="textlanding">
        <h1>Zooming in d3.js</h1>
        <hr class="short_hr" />
        <br />
        <ul class="list-inline social-buttons">
          <li class="list-inline-item">
            <a href="https://twitter.com/R_Graph_Gallery">
              <i class="fa fa-twitter"></i>
            </a>
          </li>
          <li class="list-inline-item social-buttons">
            <a href="https://github.com/holtzy">
              <i class="fa fa-github" style="color: white"></i>
            </a>
          </li>
          <li class="list-inline-item social-buttons">
            <a href="https://www.linkedin.com/in/yan-holtz-2477534a/">
              <i class="fa fa-linkedin"></i>
            </a>
          </li>
        </ul>
        <br /><br />
        <p style="max-width: 700px; margin: auto">
          This is document gives a few insights on how to add a
          <u>zooming</u> feature with d3.js. It is composed by several
          interactive examples, allowing to play with the code to understand
          better how it works.
        </p>
      </div>
    </header>

    <!-- TABLE of CONTENT -->
    <div>
      <nav class="col-sm-3 col-4" id="myScrollspy">
        <ul class="nav nav-pills flex-column">
          <li class="nav-item">
            <a class="nav-link active" href="#basiczoom">Most basic</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#axisZoom">Zoom and Pan with axis</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#brushingforzoom">Brushing for zooming</a>
          </li>
        </ul>
      </nav>
    </div>

    <!-- ==================== MOST BASIC ZOOM ==================== -->

    <section class="bg" id="basiczoom">
      <div class="container">
        <h1>Basic zoom with <code>d3.zoom()</code></h1>
        <hr />
        <div class="row">
          <!-- ==================== GRAPH SECTION = WHERE THE GRAPH APPEARS ==================== -->
          <div class="col-lg-5 .align-middle">
            <div style="position: -webkit-sticky; position: sticky; top: 120px">
              <div class="bg-light" id="res-basicZoom"></div>
              <br />
              <div>
                <h5>Notes:</h5>
                <ul>
                  <br />
                  <li>Zooming + panning. Double click zoom as well.</li>
                  <br />
                  <li>Note that the circle gets bigger when you zoom.</li>
                  <br />
                  <li>No axis</li>
                  <br />
                  <li></li>
                </ul>
              </div>
            </div>
          </div>

          <!-- ==================== CODE SECTION = WHERE THE CODE APPEARS ==================== -->
          <div class="col-lg-7 text-center .align-middle">
            <!-- ========= show html code ============== -->
            <aside
              style="position: -webkit-sticky; position: sticky; top: 120px"
            >
              &larr; Edit me!
            </aside>
            <pre
              class="language-html"
            ><code id="html-basicZoom" contenteditable="true"><xmp><!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the circle will take place -->
<div id="dataviz_basicZoom"></div>

</xmp></code></pre>
            <!-- ==================================== -->

            <!-- ========= show JS code ==============  -->
            <pre
              class="language-js"
            ><code id="js-basicZoom" contenteditable="true"><xmp><script>

// append the svg object to the body of the page
var svg = d3.select("#dataviz_basicZoom")
  .append("svg")
    .attr("width",  460)
    .attr("height",  460)
    .call(d3.zoom().on("zoom", function () {
       svg.attr("transform", d3.event.transform)
    }))
  .append("g")

svg
  .append("circle")
    .attr("cx", 300)
    .attr("cy", 300)
    .attr("r", 40)
    .style("fill", "#68b2a1")

</script></xmp></code></pre>
            <!-- ==================================== -->

            <!-- ==================== JAVASCRIPT SECTION : EXECUTE THIS CODE AND MAKE IT INTERACTIVE ==================== -->
            <script>
              // At the beginning, I read the html and JS fragments
              myHtmlParser("html-basicZoom", "res-basicZoom");
              myJSParser("js-basicZoom", "res-basicZoom");

              // If the user change the JS fragment, I run it again:
              document
                .getElementById("js-basicZoom")
                .addEventListener("input", function () {
                  d3.select("#res-basicZoom").html("");
                  myHtmlParser("html-basicZoom", "res-basicZoom");
                  myJSParser("js-basicZoom", "res-basicZoom");
                });

              // If the user change the HTML fragment, I run it again:
              document
                .getElementById("html-basicZoom")
                .addEventListener("input", function () {
                  d3.select("#res-basicZoom").html("");
                  myHtmlParser("html-basicZoom", "res-basicZoom");
                  myJSParser("js-basicZoom", "res-basicZoom");
                });
            </script>
          </div>
        </div>
      </div>
    </section>
    <br />

    <!-- ==================== ZOOM AXIS ==================== -->

    <section class="bg" id="axisZoom">
      <div class="container">
        <h1>Zoom with axis</h1>
        <hr />
        <div class="row">
          <!-- ==================== GRAPH SECTION = WHERE THE GRAPH APPEARS ==================== -->
          <div class="col-lg-5 .align-middle">
            <div style="position: -webkit-sticky; position: sticky; top: 120px">
              <div class="bg-light" id="res-axisZoom"></div>
              <br />
              <div>
                <h5>Notes:</h5>
                <ul>
                  <br />
                  <li>Same concept as before, but updates axis as well.</li>
                  <br />
                  <li>todo -> understand better</li>
                  <br />
                  <li></li>
                  <br />
                  <li></li>
                </ul>
              </div>
            </div>
          </div>

          <!-- ==================== CODE SECTION = WHERE THE CODE APPEARS ==================== -->
          <div class="col-lg-7 text-center .align-middle">
            <!-- ========= show html code ============== -->
            <aside
              style="position: -webkit-sticky; position: sticky; top: 120px"
            >
              &larr; Edit me!
            </aside>
            <pre
              class="language-html"
            ><code id="html-axisZoom" contenteditable="true"><xmp><!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the circle will take place -->
<div id="dataviz_axisZoom"></div>

</xmp></code></pre>
            <!-- ==================================== -->

            <!-- ========= show JS code ==============  -->
            <pre
              class="language-js"
            ><code id="js-axisZoom" contenteditable="true"><xmp><script>

// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 460 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// append the SVG object to the body of the page
var SVG = d3.select("#dataviz_axisZoom")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", function(data) {

  // Add X axis
  var x = d3.scaleLinear()
    .domain([4, 8])
    .range([ 0, width ]);
  var xAxis = SVG.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .domain([0, 9])
    .range([ height, 0]);
  var yAxis = SVG.append("g")
    .call(d3.axisLeft(y));

  // Add a clipPath: everything out of this area won't be drawn.
  var clip = SVG.append("defs").append("SVG:clipPath")
      .attr("id", "clip")
      .append("SVG:rect")
      .attr("width", width )
      .attr("height", height )
      .attr("x", 0)
      .attr("y", 0);

  // Create the scatter variable: where both the circles and the brush take place
  var scatter = SVG.append('g')
    .attr("clip-path", "url(#clip)")

  // Add circles
  scatter
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
      .attr("cx", function (d) { return x(d.Sepal_Length); } )
      .attr("cy", function (d) { return y(d.Petal_Length); } )
      .attr("r", 8)
      .style("fill", "#61a3a9")
      .style("opacity", 0.5)

  // Set the zoom and Pan features: how much you can zoom, on which part, and what to do when there is a zoom
  var zoom = d3.zoom()
      .scaleExtent([.5, 20])  // This control how much you can unzoom (x0.5) and zoom (x20)
      .extent([[0, 0], [width, height]])
      .on("zoom", updateChart);

  // This add an invisible rect on top of the chart area. This rect can recover pointer events: necessary to understand when the user zoom
  SVG.append("rect")
      .attr("width", width)
      .attr("height", height)
      .style("fill", "none")
      .style("pointer-events", "all")
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
      .call(zoom);
  // now the user can zoom and it will trigger the function called updateChart

  // A function that updates the chart when the user zoom and thus new boundaries are available
  function updateChart() {

    // recover the new scale
    var newX = d3.event.transform.rescaleX(x);
    var newY = d3.event.transform.rescaleY(y);

    // update axes with these new boundaries
    xAxis.call(d3.axisBottom(newX))
    yAxis.call(d3.axisLeft(newY))

    // update circle position
    scatter
      .selectAll("circle")
      .attr('cx', function(d) {return newX(d.Sepal_Length)})
      .attr('cy', function(d) {return newY(d.Petal_Length)});
  }

})
</script></xmp></code></pre>
            <!-- ==================================== -->

            <!-- ==================== JAVASCRIPT SECTION : EXECUTE THIS CODE AND MAKE IT INTERACTIVE ==================== -->
            <script>
              // At the beginning, I read the html and JS fragments
              myHtmlParser("html-axisZoom", "res-axisZoom");
              myJSParser("js-axisZoom", "res-axisZoom");

              // If the user change the JS fragment, I run it again:
              document
                .getElementById("js-axisZoom")
                .addEventListener("input", function () {
                  d3.select("#res-axisZoom").html("");
                  myHtmlParser("html-axisZoom", "res-axisZoom");
                  myJSParser("js-axisZoom", "res-axisZoom");
                });

              // If the user change the HTML fragment, I run it again:
              document
                .getElementById("html-axisZoom")
                .addEventListener("input", function () {
                  d3.select("#res-axisZoom").html("");
                  myHtmlParser("html-axisZoom", "res-axisZoom");
                  myJSParser("js-axisZoom", "res-axisZoom");
                });
            </script>
          </div>
        </div>
      </div>
    </section>
    <br />

    <!-- ==================== BRUSHING FOR ZOOMING ==================== -->

    <section class="bg" id="brushingforzoom">
      <div class="container">
        <h1>Brushing for zooming</h1>
        <hr />
        <div class="row">
          <!-- ==================== GRAPH SECTION = WHERE THE GRAPH APPEARS ==================== -->
          <div class="col-lg-5 .align-middle">
            <div style="position: -webkit-sticky; position: sticky; top: 120px">
              <div class="bg-light" id="res-brushZoom"></div>
              <br />
              <div>
                <h5>Notes:</h5>
                <ul>
                  <br />
                  <li>
                    Select a zone to zoom on it (X axis only). Double click to
                    unzoom.
                  </li>
                  <br />
                  <li>
                    A <code>clipPath</code> is used to avoid displaying the
                    circle outside the chart area.
                  </li>
                  <br />
                  <li>
                    <code>all(brush.move, null)</code> is used to dismiss the
                    grey brushing area once the selection has been done.
                  </li>
                  <br />
                  <li>
                    But this leads to synchronization problems: the brush
                    boundaries are erased as soon as the selection is done -->
                    It is necessary to wait a little bit to have time to update
                    axis and circles
                  </li>
                </ul>
              </div>
            </div>
          </div>

          <!-- ==================== CODE SECTION = WHERE THE CODE APPEARS ==================== -->
          <div class="col-lg-7 text-center .align-middle">
            <!-- ========= show html code ============== -->
            <aside
              style="position: -webkit-sticky; position: sticky; top: 120px"
            >
              &larr; Edit me!
            </aside>
            <pre
              class="language-html"
            ><code id="html-brushZoom" contenteditable="true"><xmp><!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the circle will take place -->
<div id="dataviz_brushZoom"></div>

</xmp></code></pre>
            <!-- ==================================== -->

            <!-- ========= show JS code ==============  -->
            <pre
              class="language-js"
            ><code id="js-brushZoom" contenteditable="true"><xmp><script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 460 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var Svg = d3.select("#dataviz_brushZoom")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", function(data) {

  // Add X axis
  var x = d3.scaleLinear()
    .domain([4, 8])
    .range([ 0, width ]);
  var xAxis = Svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .domain([0, 9])
    .range([ height, 0]);
  Svg.append("g")
    .call(d3.axisLeft(y));

  // Add a clipPath: everything out of this area won't be drawn.
  var clip = Svg.append("defs").append("svg:clipPath")
      .attr("id", "clip")
      .append("svg:rect")
      .attr("width", width )
      .attr("height", height )
      .attr("x", 0)
      .attr("y", 0);

  // Color scale: give me a specie name, I return a color
  var color = d3.scaleOrdinal()
    .domain(["setosa", "versicolor", "virginica" ])
    .range([ "#440154ff", "#21908dff", "#fde725ff"])

  // Add brushing
  var brush = d3.brushX()                 // Add the brush feature using the d3.brush function
      .extent( [ [0,0], [width,height] ] ) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
      .on("end", updateChart) // Each time the brush selection changes, trigger the 'updateChart' function

  // Create the scatter variable: where both the circles and the brush take place
  var scatter = Svg.append('g')
    .attr("clip-path", "url(#clip)")

  // Add circles
  scatter
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
      .attr("cx", function (d) { return x(d.Sepal_Length); } )
      .attr("cy", function (d) { return y(d.Petal_Length); } )
      .attr("r", 8)
      .style("fill", function (d) { return color(d.Species) } )
      .style("opacity", 0.5)

  // Add the brushing
  scatter
    .append("g")
      .attr("class", "brush")
      .call(brush);

  // A function that set idleTimeOut to null
  var idleTimeout
  function idled() { idleTimeout = null; }

  // A function that update the chart for given boundaries
  function updateChart() {

    extent = d3.event.selection

    // If no selection, back to initial coordinate. Otherwise, update X axis domain
    if(!extent){
      if (!idleTimeout) return idleTimeout = setTimeout(idled, 350); // This allows to wait a little bit
      x.domain([ 4,8])
    }else{
      x.domain([ x.invert(extent[0]), x.invert(extent[1]) ])
      scatter.select(".brush").call(brush.move, null) // This remove the grey brush area as soon as the selection has been done
    }

    // Update axis and circle position
    xAxis.transition().duration(1000).call(d3.axisBottom(x))
    scatter
      .selectAll("circle")
      .transition().duration(1000)
      .attr("cx", function (d) { return x(d.Sepal_Length); } )
      .attr("cy", function (d) { return y(d.Petal_Length); } )

    }



})

</script></xmp></code></pre>
            <!-- ==================================== -->

            <!-- ==================== JAVASCRIPT SECTION : EXECUTE THIS CODE AND MAKE IT INTERACTIVE ==================== -->
            <script>
              // At the beginning, I read the html and JS fragments
              myHtmlParser("html-brushZoom", "res-brushZoom");
              myJSParser("js-brushZoom", "res-brushZoom");

              // If the user change the JS fragment, I run it again:
              document
                .getElementById("js-brushZoom")
                .addEventListener("input", function () {
                  d3.select("#res-brushZoom").html("");
                  myHtmlParser("html-brushZoom", "res-brushZoom");
                  myJSParser("js-brushZoom", "res-brushZoom");
                });

              // If the user change the HTML fragment, I run it again:
              document
                .getElementById("html-brushZoom")
                .addEventListener("input", function () {
                  d3.select("#res-brushZoom").html("");
                  myHtmlParser("html-brushZoom", "res-brushZoom");
                  myJSParser("js-brushZoom", "res-brushZoom");
                });
            </script>
          </div>
        </div>
      </div>
    </section>
    <br />

    <!-- ============================ RELATED BLOCKS ============================ -->

    <section
      id="related"
      class="bg-light"
      style="padding-top: 70px; padding-bottom: 70px"
    >
      <div class="container">
        <div class="row">
          <div
            class="col-lg-5 text-center .align-middle"
            style="border-right: solid"
          >
            <div style="display: table; height: 150px; overflow: hidden">
              <div style="display: table-cell; vertical-align: middle">
                <h2 class="section-heading text-uppercase" style="color: black">
                  Related blocks
                </h2>
              </div>
            </div>
          </div>
          <div class="col-lg-5">
            <div style="display: table; height: 150px; overflow: hidden">
              <div style="display: table-cell; vertical-align: middle">
                <ul>
                  <li>
                    <i>Simplest way to add zoom/pan on d3.js- </i>by
                    <a
                      href="https://coderwall.com/p/psogia/simplest-way-to-add-zoom-pan-on-d3-js"
                      >Sébastien Gruhier.</a
                    >
                  </li>
                  <br />
                  <li>
                    <i>Click-to-Recenter Brush - </i>by
                    <a href="https://bl.ocks.org/mbostock/6498000"
                      >Mike Bostock</a
                    >
                  </li>
                  <br />
                  <li>
                    <i>Scatter plot with zoom</i> - by
                    <a
                      href="https://bl.ocks.org/EfratVil/d956f19f2e56a05c31fb6583beccfda7"
                      >Efrat Vilenski</a
                    >
                  </li>
                  <br />
                  <li>
                    <i>D3 v4 - Scatter Plot - Semantic Zooming</i> - by
                    <a
                      href="https://bl.ocks.org/aleereza/d2be3d62a09360a770b79f4e5527eea8"
                      >Aleereza</a
                    >
                  </li>
                </ul>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>

    <!-- ============================ CONTACT SECTION ============================ -->

    <!-- ANCHOR -->
    <a name="contactanchor"></a>

    <section id="contact" class="bg" style="background-color: white"></section>

    <!-- THIS ALLOWS TO INSERT THE CONTACT CHUNK THAT IS STORED IN A CONTACT.HTML FILE-->
    <script>
      $(function () {
        $("#contact").load("../html_chunk/contact.html");
      });
    </script>

    <!-- ============================ FOOTER SECTION ============================ -->
    <footer class="bg-light" id="myFooter"></footer>

    <!-- Start Added by AdThrive -->
    <script
      type="text/javascript"
      async
      src="https://btloader.com/tag?o=5698917485248512&upapi=true&domain=d3-graph-gallery.com"
    ></script>
    <script>
      !(function () {
        "use strict";
        var e;
        (e = document),
          (function () {
            var t, n;
            function r() {
              var t = e.createElement("script");
              (t.src =
                "https://cafemedia-com.videoplayerhub.com/galleryplayer.js"),
                e.head.appendChild(t);
            }
            function a() {
              var t = e.cookie.match("(^|[^;]+)\s*__adblocker\s*=\s*([^;]+)");
              return t && t.pop();
            }
            function c() {
              clearInterval(n);
            }
            return {
              init: function () {
                var e;
                "true" === (t = a())
                  ? r()
                  : ((e = 0),
                    (n = setInterval(function () {
                      (100 !== e && "false" !== t) || c(),
                        "true" === t && (r(), c()),
                        (t = a()),
                        e++;
                    }, 50)));
              },
            };
          })().init();
      })();
    </script>
    <!-- End Added by AdThrive -->

    <!-- THIS ALLOWS TO INSERT THE FOOTER THAT IS STORED IN A FOOTER.HTML FILE-->
    <script>
      $(function () {
        $("#myFooter").load("../html_chunk/footer.html");
      });
    </script>

    <!-- ============================ -->
  </body>
</html>
